//
//  ZYOCExceptionHandler.m
//  ZYWebImage
//
//  Created by wangzhipan on 2025/5/3.
//

#import "ZYOCExceptionHandler.h"
#import "ZYCrashReportGenerator.h"
//保存之前的异常处理函数
static NSUncaughtExceptionHandler *previousExceptionHandler = nil;

//是否已经install
static BOOL isHandlerInstalled = NO;

static void ZYHandleException(NSException * exception)
{
    // 防止递归崩溃
    static BOOL isHandlingException = NO;
    if (isHandlingException) {
        return;
    }
    isHandlingException = YES;
    
    NSMutableDictionary *crashInfo = [NSMutableDictionary dictionaryWithDictionary:exception.userInfo];
    crashInfo[@"reason"] = exception.reason;
    crashInfo[@"name"] = exception.name;
    crashInfo[@"callStackSymbols"] = exception.callStackSymbols;
    
    [[ZYCrashReportGenerator sharedInstance] generateReportWithType:ZYCrashTypeException
                                                               name:exception.name
                                                             reason:exception.reason
                                                           userInfo:crashInfo];
    // 调用之前的异常处理函数
    isHandlingException = NO;
    if (previousExceptionHandler) {
        previousExceptionHandler(exception);
    }
    
    // 如果没有之前的处理器或者之前的处理器没有终止程序，我们需要确保程序终止
    // 这里使用 kill 而不是 abort() 是为了避免产生额外的崩溃报告
    kill(getpid(), SIGKILL);
}

@implementation ZYOCExceptionHandler
- (BOOL)install
{
    if (isHandlerInstalled) {
        return YES;
    }
    
    @synchronized (self) {
        // 再次检查，防止多线程问题
        if (isHandlerInstalled) {
            return YES;
        }
        // 保存之前的异常处理函数
        previousExceptionHandler = NSGetUncaughtExceptionHandler();
        //设置我们的异常处理函数
        NSSetUncaughtExceptionHandler(ZYHandleException);
        
        isHandlerInstalled = YES;
        return YES;
    }
}

- (void)uninstall
{
    @synchronized (self) {
        if (!isHandlerInstalled) {
            return;
        }
        
        //恢复之前的异常处理函数
        if (previousExceptionHandler) {
            NSSetUncaughtExceptionHandler(previousExceptionHandler);
        }
        previousExceptionHandler = NULL;
        isHandlerInstalled = NO;
    }
}
@end
